home *** CD-ROM | disk | FTP | other *** search
/ PC-X 1997 October / pcx14_9710.iso / swag / delphi.swg / 0202_Delphi Components Writing.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-11-29  |  13.1 KB  |  404 lines

  1.  
  2. I notices that the Delphi FAQ has not been updated in over a year.  Since much 
  3. of the information needed to write Delphi components is undocumented I thought 
  4. that maybe there should be a component writing FAQ.
  5.  
  6. I have been going through some of my source code to get some of the tricks 
  7. that I have had to use in writing components.  I am going through my mail to 
  8. see what tricks people have sent me and I will attempt to give credit to those 
  9. who have mailed me information.
  10.  
  11. Right now this document is short but hopefully it will grow over time.  Some 
  12. of the information enclose has never been published.  If you have 
  13. something to contribute or suggestions then mail them to me.
  14.  
  15. So hear goes......
  16.  
  17.  
  18. The Unofficial Delphi Component Writing FAQ
  19.  
  20. Maintainer:     John M. Miano   miano@worldnet.att.net
  21. Version:        1
  22. Last Updated:   30-Aug-96
  23.  
  24. ------------------------------------------------------------------------
  25. Table of Contents
  26.  
  27. Section 1 - Introduction
  28. 1.1. What is the purpose of this document?
  29.  
  30. Section 2 - IDE 
  31. 2.1. How can I locate problems the result when my component is used in the 
  32. IDE?
  33. 2.2. How do I view assembly langugage the Delphi Generates?
  34. 2.3. I can create my control at run time but it crashes at design time.  What 
  35. is wrong?
  36. 2.4. How can I make my control work only in design mode?
  37.  
  38. Section 3 - Using other components within a component
  39. 3.1. How can I add a scroll bar component to my component and have it work at
  40. in design mode?
  41. 3.2. How do I create a Windows '95-style scroll bar?
  42.  
  43. Section 4 - Bound Controls
  44. 4.1. Where is the documentation for the TDataLink class?
  45.  
  46. Section 5 - VCL
  47. 5.1. How can I step through the VCL source while debugging
  48.  
  49. Section 6 - Other Sources of Information
  50. 6.1. Are there any books one how to write Delphi components?
  51.  
  52. Section 7 - Persistant Objects
  53. 7.1. How can I save a complex object containing child objects to the .DFM 
  54. file.
  55.  
  56. ------------------------------------------------------------------------
  57. Section 1 - Introductions
  58.  
  59. 1.1. What is the purpose of this document?
  60.  
  61. The purpose of this document is to answer common or undocumented questions
  62. related to writing Delphi components.  This information is provided as is.  
  63. There are no guarentee as to its correctness.  If you find error or ommissions 
  64. sent them to the author.
  65.  
  66. This document is rather short at the moment but hopefully it will grow over 
  67. time.
  68.  
  69. ------------------------------------------------------------------------
  70. Section 2 - IDE Problems
  71.  
  72. 2.1. How can I locate problems the result when my component is used in the 
  73. IDE?
  74.  
  75. The only solution to locating problems I have found it to:
  76.  
  77. 1. In Delphi go to Tools/Options then go to the "Library" page.
  78. Check the "Compile With Debug Info" box.
  79. 2. Rebuild the library.
  80. 3. Run Delphi from within Turbo Debugger.
  81.  
  82. If you get a GPF you can use view the stack and get some idea where the 
  83. problem is occuring.
  84.  
  85. 2.2. How do I view assembly langugage the Delphi Generates?
  86.  
  87. From Glen Boyd
  88.  
  89. Borland/Delphi/2.0/Debugging add a string value called EnableCPU and set
  90. its string value to 1.  This add the CPU window to the view menu.  The CPU 
  91. window is
  92. active at run time for stepping through and stuff like that.
  93.  
  94. 2.3. I can create my control at run time but it crashes at design time.  What 
  95. is wrong?
  96.  
  97. 1. You component must descent from TComponent
  98.  
  99. 2. Your constructory and destructor declarations must look like:
  100.  
  101. Constructor Create (AOwner : TComponent) ; Override ;
  102. Destructor Destroy ; Override ;
  103.  
  104. 3  You will get an Access Violation/GPF if you component has any published 
  105. properties that do not have a property editor defined.  These include array 
  106. properties and properties of types you create. 
  107.  
  108. How do I make a component work only in design mode?
  109.  
  110. The trick is to use the Register function.  This is only called in design 
  111. mode.  You can
  112. use it to set a flag that your constructors can check.
  113.  
  114. 2.4. How can I make my control work only in design mode?
  115.  
  116. The Register procedure is only called in design mode.  You can define a flag 
  117. in your module and have your register procedure set that flag.  If that flag 
  118. is clear in your constructor then you are not in design mode.
  119.  
  120. ------------------------------------------------------------------------
  121. Section 3 - Using other components within a component
  122.  
  123. 3.1. How can I add a scroll bar component to my component and have it work at 
  124. in design mode?
  125.  
  126. You need to define your own scroll bar class that intercepts the 
  127. CM_DESIGNHITTEST message.
  128.  
  129. TMyScrollBar = class (TScrollBar)
  130.       Procedure CMDesignHitTest (var Message : TCMDesignHitTest) ; Message 
  131. CM_DESIGNHITTEST ;
  132.     End ;
  133.  
  134. Procedure TMyScrollBar.CMDesignHitTest (var Message : TCMDesignHitTest) ;
  135.   Begin
  136.   Message.Result := 1 ;
  137.   End ;
  138.  
  139. When your component creates one of these scroll bars it needs to use
  140.  
  141. TMyScrollBar.Create (Nil) 
  142.  
  143. rather then
  144.  
  145. TMyScrollBar.Create (Self)
  146.  
  147. otherwise the scroll bar will display sizing handles when it is click.   This 
  148. means you need to be sure to explicitly free the scroll bar in your
  149. component's destructor.
  150.  
  151. 3.2 How do I create a Windows '95-style scroll bar?
  152.  
  153. You need to set the page size for the scroll bar.   The following code
  154. sequence
  155. illustrates this:
  156.  
  157. Procedure SetPageSize (ScrollBar : TScrollBar ; PageSize : Integer) ;
  158.   Var
  159.     ScrollInfo : TScrollInfo ;
  160.   Begin
  161.   ScrollInfo.cbSize := Sizeof (ScrollInfo) ;
  162.   ScrollInfo.fMask := SIF_PAGE ;
  163.   ScrollInfo.nPage := PageSize ;   
  164.   SetScrollInfo (ScrollBar.Handle, SB_CTL, ScrollInfo, True) ;
  165.   End ;
  166.  
  167. To retrieve the page size use:
  168.  
  169. Function GetpageSize (ScrollBar : TScrollBar) ;
  170.   Var
  171.     ScrollInfo : TScrollInfo ;
  172.   Begin
  173.   If HandleAllocated Then
  174.     Begin
  175.     ScrollInfo.cbSize := Sizeof (ScrollInfo) ;
  176.     ScrollInfo.fMask := SIF_PAGE ;
  177.     GetScrollInfo (ScrollBar.Handle, SB_CTL, ScrollInfo) ;
  178.     Result := ScrollInfo.nPage ;
  179.     End ;
  180.  
  181. ------------------------------------------------------------------------
  182. Section 4 - Bound Controls
  183.  
  184. 4.1. Where is the documentation for the TDataLink class?
  185.  
  186. As far as I can tell the only documentation for TDataLink that exists in the 
  187. entire universe is what follows
  188.  
  189. Properties:
  190. ===========
  191.  
  192. Property:       Active : Boolean (Read Only)
  193. ----------------------------------------
  194.  
  195. Returns true when the data link is connected to an active datasource.
  196. The ActiveChanged method is called to give notification when the state
  197. changes.
  198.  
  199. Property:       ActiveRecord: (Read/Write)
  200. --------------------------------------
  201.  
  202. This sets or returns the current record within the TDatalink's buffer window.  
  203. Valid values are
  204. 0..BufferCount - 1.  There appear to be no range checks so assigning values 
  205. outside this range produces unpredictable results.
  206.  
  207. Property:       BufferCount: (Read/Write)
  208. -------------------------------------
  209.  
  210. The TDataLink maintains a window of records into the dataset  This property is
  211. the size of this window and determines the maximum number of row that can be 
  212. view simultaneously.  For most controls you would use a BufferCount of one.  
  213. For controls such as a data grid this value is the number of visible rows.
  214.  
  215. Property:       DataSet: TDataSet (Read)
  216. ------------------------------------
  217.  
  218. The dataset the TDataLink is attached to.  This is a shortcut to 
  219. DataSource.DataSet.
  220.  
  221. Property:       DataSource: TDataSource (Read/Write)
  222. ------------------------------------------------
  223.  
  224. Sets or returns data source control the TDataLink is attached to.
  225.  
  226. Property:       DataSourceFixed: Boolean (Read/WRite)
  227. -------------------------------------------------
  228.  
  229. This property is used to prevent the data source for the TDataLink from being
  230. changed.  If this property is set to Trye then assigning a value to the 
  231. DataSource property will result in an exception.
  232.  
  233. Property:       Editing: Boolean (Read Only)
  234. ----------------------------------------
  235.  
  236. Returns true if the datalink is in edit mode.
  237.  
  238. Property:       ReadOnly: Boolean (read/Write)
  239. ------------------------------------------
  240.  
  241. This property determines if the TDataLink is read only.  It does not appear to
  242. affect the attached datalink
  243. or dataset.  If this property is set to True the datalink will not go into 
  244. edit mode.
  245.  
  246. Property:       RecordCount: Integer (Read)
  247. ---------------------------------------
  248.  
  249. The property returns the approximate number of records in the attached 
  250. dataset.
  251.  
  252. Methods:
  253. ========
  254.  
  255. function Edit: Boolean;
  256. -----------------------
  257.  
  258. Puts the TDatalink's attached dataset into edit mode.
  259.  
  260. Return Value:
  261.         True => Success
  262.         False => Failure
  263.  
  264. procedure UpdateRecord;
  265. -----------------------
  266.  
  267. It appears that this is a function that is intended to be called by other
  268. parts of the data base interface and should not be called directly.  All it
  269. does is set a flag and call UpdateData (described below).
  270.  
  271.  
  272. Virtual Methods
  273. ===============
  274.  
  275. The mechanism for having the TDataLink object communicate with a component is 
  276. to override these procedures.
  277.  
  278. procedure ActiveChanged
  279. ------------------------
  280.  
  281. This procedure is called whenever the datasource the TDataLink is attached to 
  282. becomes active or
  283. inactive.  Use the Active property to determine whether or not the link is 
  284. active.
  285.  
  286. procedure CheckBrowseMode
  287. -------------------------
  288.  
  289. This method appears to get called before any changes take place to the
  290. database.
  291.  
  292. procedure DataSetChanged;
  293. -------------------------
  294.  
  295. This procedure gets called when the following events occur:
  296.  
  297.    o  Moving to the start of the dataset
  298.    o Moving to the end of the dataset
  299.    o Inserting or Appending to the dataset
  300.    o Deleting a record from the dataset
  301.    o Canceling the editing of a record
  302.    o Updating a record
  303.  
  304. The non-overrident action for this procedure is to call
  305.         RecordChanged (Nil)
  306.  
  307. procedure DataSetScrolled(Distance: Integer)
  308. --------------------------------------------
  309.  
  310. This procedure is called whenever the current record in the dataset changes.  
  311. The Distance parameter tells how far the buffer window into the dataset was 
  312. scrolled (This seems to always be in the range -1, 0, 1).
  313.  
  314. Use the ActiveRecord to determine which record within the buffer window is the 
  315. current one.
  316.  
  317. It is not possible to force a scroll of the buffer window.
  318.  
  319. procedure FocusControl(Field: TFieldRef)
  320. ----------------------------------------
  321.  
  322. This appears to get called as a result of Field.FocusControl.
  323.  
  324. procedure EditingChanged
  325. -------------------------
  326.  
  327. This procedure is called when the editing state of the TDataLink changes.  Use 
  328. the Editing property to determine if the TDataLink is in edit mode or not.
  329.  
  330. procedure LayoutChanged
  331. -----------------------
  332.  
  333. This procedure is called when the layout of the attached dataset changes (e.g. 
  334. column added) .
  335.  
  336. procedure RecordChanged(Field: TField)
  337. --------------------------------------
  338.  
  339. This procedure gets called when:
  340.  
  341.    o The current record is edited
  342.    o The record's text has changed
  343.  
  344. If the Field parameter is non-nil then the change occured to the specified 
  345. field.
  346.  
  347. procedure UpdateData
  348. --------------------
  349.  
  350. This procedure is called immediately before a record is updated in the 
  351. database.  You can call the Abort procedure to prevent the record from being 
  352. updated.
  353.  
  354.  
  355. ------------------------------------------------------------------------
  356. Section 5 - VCL
  357. 5.1. How can I step through the VCL source while debugging
  358.  
  359. Copy the VCL source modules you are interested in stepping through to your 
  360. project directory then rebuild the VCL library.  You will then be able to step 
  361. through the VCL source modules.
  362.  
  363. ------------------------------------------------------------------------
  364. Section 6 - Other Sources of Information
  365.  
  366. 6.1. Are there any books one how to write Delphi components?
  367.  
  368. I have seen a couple out there but the only one I can recommend is
  369.  
  370. "Developing Delphi Components" by Ray Konopka
  371.  
  372. ------------------------------------------------------------------------
  373. Section 7 - Persistant Objects
  374.  
  375. 7.1. How can I save a complex object containing child objects to the .DFM 
  376. file.
  377.  
  378. I have tried all sorts of schemes using DefineProperties and WriteComponents 
  379. and they all failed to work. As far as I can the only way to do this is to use 
  380. Delphi's default mechanism to store your child objects.  
  381.  
  382. A sequence that does work for saving to a stream is:
  383.  
  384. 1. Make all of the classes whose objects you want to save descent from 
  385. TComponent.
  386. 2. Make all of the values you want to save published.
  387. 3. Within your Register procedure add a call to RegisterComponents containing 
  388. all of the classes you wish to store.
  389. 4. Each class that owns child classes needs to overload the procedure 
  390. GetChildren.  Within this procedure is needs to call the procedure passed as 
  391. an argument for each child to be stored.
  392.  
  393. Getting the objects out of the stream is a little trickier.  Your parent 
  394. object may need to overload the GetChildOwner and GetChildParent functions.  
  395. Otherwise Delphi will try to make the child owned by the form.
  396.  
  397.  
  398. ------------------------------------------------------------------------
  399. Copyright 1996 - John Miano
  400.  
  401. Contributers
  402.  
  403. Glen Boyd
  404.